package common.utils;

import io.qameta.allure.Allure;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.testng.Reporter;

import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * 日志工具类
 *
 * @author Vincent-Li
 */
public class LeoLogger {
    /**
     * 获取最原始被调用的堆栈信息
     *
     * @return StackTraceElement
     * @author Vincent-Li
     */
    private static StackTraceElement findCaller() {
        // 获取堆栈信息
        StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
        //noinspection ConstantConditions
        if (null == callStack) return null;

        // 最原始被调用的堆栈信息
        StackTraceElement caller = null;
        // 日志类名称
        String logClassName = LeoLogger.class.getName();
        // 循环遍历到日志类标识
        boolean isEachLogClass = false;

        // 遍历堆栈信息，获取出最原始被调用的方法信息
        for (StackTraceElement s : callStack) {
            // 遍历到日志类
            if (logClassName.equals(s.getClassName())) {
                isEachLogClass = true;
            }
            // 下一个非日志类的堆栈，就是最原始被调用的方法
            if (isEachLogClass) {
                if (!logClassName.equals(s.getClassName())) {
                    isEachLogClass = false;
                    caller = s;
                    break;
                }
            }
        }
        return caller;
    }

    /**
     * 自动匹配请求类名，生成logger对象，此处 logger name 值为 [className].[methodName]() Line: [fileLine]
     *
     * @return logger
     * @author Vincent-Li
     */
    private static Logger logger() {
        // 最原始被调用的堆栈对象
        StackTraceElement caller = findCaller();
        if (null == caller) return LogManager.getLogger(LeoLogger.class);
        return LogManager.getLogger(getSimpleClassName(caller.getClassName()) + "." + caller.getMethodName()
                + "() Line:" + caller.getLineNumber());
    }

    public static void trace(String msg) {
        trace(msg, null);
    }

    public static void trace(String msg, Throwable e) {
        logger().trace(msg, e);
    }

    public static void debug(String msg) {
        debug(msg, null);
    }

    public static void debug(String msg, Throwable e) {
        logger().debug(msg, e);
    }

    public static void info(String msg) {
        info(msg, null);
    }

    public static void info(String msg, Throwable e) {
        Logger logger = logger();
        logger.info(msg, e);
        Reporter.log(addTimeTag("[INFO] " + logger.getName() + " - " + msg));
    }

    public static void warn(String msg) {
        warn(msg, null);
    }

    public static void warn(String msg, Throwable e) {
        Logger logger = logger();
        logger.warn(msg, e);
        Reporter.log(addTimeTag("[WARN] " + logger.getName() + " - " + msg));
    }

    public static void error(String msg) {
        error(msg, null);
    }

    public static void error(String msg, Throwable e) {
        Logger logger = logger();
        logger.error(msg, e);
        Reporter.log(addTimeTag("[ERROR] " + logger.getName() + " - " + msg));
    }

    public static void logCaseStep(String msg) {
        Logger logger = logger();
        logger.info(msg);
        Reporter.log(addTimeTag("[STEP] " + logger.getName() + " - " + msg));
        Allure.step(msg);
    }

    public static void setTestStep(String msg) {
        Logger logger = logger();
        // add asterisk before and after the message and the whole line will compose of 100 characters
        int asterisk = (100 - logger.getName().length() - msg.length()) / 2;
        String message = StringUtils.repeat("*", asterisk) + msg
                + StringUtils.repeat("*", asterisk + ((100 - msg.length()) % 2));
        logger.info(message);
    }

    private static String addTimeTag(String message) {
        Long timeStamp = System.currentTimeMillis();
        String dateString = timestampToDate(timeStamp);
        return "[" + dateString + "] " + message;
    }

    // 时间戳转date字符串
    private static String timestampToDate(Long timestamp) {
        if (timestamp.toString().length() < 13) {
            timestamp = Long.valueOf(timestamp.toString().substring(0, 10) + "000");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(timestamp);
        return sdf.format(date);
    }

    // 去掉包名，只保留类名
    private static String getSimpleClassName(String allName) {
        String[] className = allName.split("\\.");
        return className[className.length - 1];
    }
}
